; void waves_c (
;	unsigned char *src,
;	unsigned char *dst,
;	int m,
;	int n,
;	int row_size,
;	float x_scale,
;	float y_scale,
;	float g_scale
; );

; Parámetros:
; 	rdi = src
; 	rsi = dst
; 	rdx = m
; 	rcx = n
; 	r8 = row_size
; 	xmm0 = x_scale
; 	xmm1 = y_scale
; 	xmm2 = g_scale


global waves_asm

section .data
	pos_i_actual		dd 0
	pos_j_actual 		dd 0
	cte_1	 		dd 1
	cte_8	 		dd 8
	cte_2			dd 2
	cte_seis		dd 6
	cte_ciento_veinte	dd 120
	cte_mucho		dd 5040
	PI			dd 3.1415

	x_scale 		dd 0
	y_scale 		dd 0
	g_scale 		dd 0

	tmp_calc		dd 0,0,0,0


section .text

waves_asm:
	push rbp
	mov rbp, rsp
	push rbx
        push r12 
        push r13
        push r14
        push r15

	mov r14, r8			; r14 : row_size
	mov r15, rdx			; r15 : cant filas
	mov r12, 0			; r12 : columna actual
	mov r13, 0			; r13 : cantidad de filas copiadas

	movd [x_scale], xmm0
	movd [y_scale], xmm1
	movd [g_scale], xmm2

.procesarImagen:
	
		mov r11, r12
		add r11, 16
		cmp r11, r14
		jbe .moverDatos
		mov r12, r14
		sub r12, 16

		.moverDatos:
			mov rcx, 4
			.procesar16bytes:
				mov dword [pos_i_actual], r13d
				mov dword [pos_j_actual], r12d

				pxor xmm0, xmm0
				movd xmm0, [rdi + r12]			; movemos 4 bytes de A

				push rcx
				call calcularValorDst			
				pop rcx

				movd [rsi + r12], xmm0

				add r12, 4
				loop .procesar16bytes
				sub r12, 16

		add r12, 16
		cmp r12, r14
		jb .procesarImagen
		je .siguienteFila
		
	.siguienteFila:
			mov r12, 0		; volvemos a empezar de la columna 0

			; movemos src y dst a la siguiente file
			add rdi, r14
			add rsi, r14


			; actualizamos filas
			inc r13
			cmp r13, r15		; copiamos todas las filas?
			jge .imagenFin

			jmp .procesarImagen

.imagenFin:


	pop r15
        pop r14
        pop r13
        pop r12
        pop rbx
	pop rbp

	ret



; auxiliar
; float calcularValorDst(float input4Ints)
calcularValorDst:
	push rbp
	mov rbp, rsp
	push rbx
        push r12 
        push r13
        push r14
        push r15

	pxor xmm7, xmm7
	punpcklbw xmm0, xmm7 
	punpcklwd xmm0, xmm7
	movdqu xmm7, xmm0			; xmm7 = a_i_j+3   a_i_j+2    a_i_j+1    a_i_j


	
	; procurar no modificar xmm7 pues es el parametro de entrada
	
		; -------------  inicio superior izquierdo de prof_i_j -------------------------

			pxor xmm6, xmm6
			movd xmm6, [cte_8]			; xmm6 = 0 0 0 8
			shufps xmm6, xmm6, 0h			; xmm6 = 8 8 8 8
			cvtdq2ps xmm6, xmm6			; xmm6 = 8.0   8.0   8.0   8.0

			pxor xmm5, xmm5
			movd xmm5, [pos_i_actual]		; xmm5 = 0 0 0 i
			shufps xmm5, xmm5, 0h			; xmm5 = i i i i
			cvtdq2ps xmm5, xmm5			; xmm5 = i.0   i.0   i.0   i.0

			divps xmm5, xmm6
			movdqu xmm0, xmm5 			; xmm0 = i/8 i/8 i/8 i/8
			call sin_taylor
			movdqu xmm5, xmm0			; xmm5 = resultado sin_taylor 


			movd xmm0, [x_scale]
			shufps xmm0, xmm0, 0h
			mulps xmm5, xmm0			; xmm5 = x_xcale * sin_taylor(i)	

			movups [tmp_calc], xmm5
		; -------------  fin superior izquierdo de prof_i_j -------------------------


				
		; -------------  inicio superior derecho de prof_i_j -------------------------
			
			pxor xmm4, xmm4
			movd xmm4, [pos_j_actual] 
			shufps xmm4, xmm4, 0h			; xmm4 = j j j j
			movd xmm6, [cte_1]
			shufps xmm6, xmm6, 0h			; xmm6 = 1 1 1 1

			xor rcx, rcx
			mov rcx, 4

			.initJ:
				pslldq xmm6, 4	
				paddd xmm4, xmm6 
				loop .initJ
				; xmm4 = j+3 j+2 j+1 j

			cvtdq2ps xmm4, xmm4			; xmm4 = (j+3).0   (j+1).0   (j+1).0   j.0

			pxor xmm6, xmm6
			movd xmm6, [cte_8]			; xmm6 = 0 0 0 8
			shufps xmm6, xmm6, 0h			; xmm6 = 8 8 8 8
			cvtdq2ps xmm6, xmm6			; xmm6 = 8.0   8.0   8.0   8.0

			divps xmm4, xmm6			; xmm4 = (j+3)/8   (j+2)/8   (j+1)/8   (j/8)
			movdqu xmm0, xmm4 
			call sin_taylor	
			movdqu xmm4, xmm0

			movd xmm0, [y_scale]
			shufps xmm0, xmm0, 0h
			mulps xmm4, xmm0
		; -------------  fin superior derecho de prof_i_j -------------------------

			movups xmm5, [tmp_calc]
			addps xmm5, xmm4			; parte superior division en prof_i_j


			pxor xmm4, xmm4				; xmm4 = 0 0 0 0
			movd xmm4, [cte_2]			; xmm4 = 0 0 0 2
			shufps xmm4, xmm4, 0h			; xmm4 = 2 2 2 2	
			cvtdq2ps xmm4, xmm4			; xmm6 = 2.0   2.0   2.0   2.0

			divps xmm5, xmm4			; xmm5 = prof_i_j


			pxor xmm4, xmm4				; xmm4 = 0 0 0 0
			movd xmm4, [g_scale]
			shufps xmm4, xmm4, 0h
			mulps xmm5, xmm4			; xmm5 = prof_i_j * g_scale

			
			; transformo los 4 bytes de xmm7 a float y los sumo a xmm5
			cvtdq2ps xmm7, xmm7			; xmm7 = (j+3).0   (j+2).0   (j+1).0    j.0
			addps xmm5, xmm7			; xmm5 = 4 pixels procesados

			; xmm5 = los 4 floats se pasaron a double words
			cvtps2dq xmm5, xmm5			

			; falta redondear a [0,255] cada uno de los 4 double words en xmm5 y pasarlos a byte
			packssdw xmm5, xmm5
			packuswb xmm5, xmm5
			
			; devuelvo los 4 pixels procesados en el primer double word de xmm0
			pxor xmm0, xmm0
			movdqu xmm0, xmm5

		; --------------------------------------------

	pop r15
        pop r14
        pop r13
        pop r12
        pop rbx
	pop rbp

	ret


sin_taylor: 
	; input x = xmm0
	; outpút = xmm0
	; registros que usa:
	;	xmm0
	;	xmm1
	; 	xmm2
	; 	xmm3
	; 	xmm4
	;	xmm5
	;	xmm6

	movdqu xmm2, xmm0		; xmm2 = parametro de entrada
	movdqu xmm4, xmm0		; xmm4 = parametro de entrada
	

	movd xmm1, [PI]
	shufps xmm1, xmm1, 0h		; xmm1 = pi pi pi pi
			
	pxor xmm3, xmm3
	movd xmm3, [cte_2]
	shufps xmm3, xmm3, 0h		; xmm3 = 2 2 2 2
	cvtdq2ps xmm3, xmm3		; xmm4 = 2.0   2.0   2.0   2.0

	mulps xmm1, xmm3		; xmm1 = 2pi 2pi 2pi 2pi

	divps xmm0, xmm1		; xmm0 = x3/2pi   x2/2pi    x1/2pi   x0/2pi

	cvttps2dq xmm0, xmm0		; xmm0 = k k k k			-> redondeo
	cvtdq2ps xmm0, xmm0		; xmm4 = k.0  k.0  k.0  k.0

	mulps xmm0, xmm1		; xmm2 = 2kpi 2kpi 2kpi 2kpi 

	subps xmm2, xmm0		; xmm2 = r r r r

	movd xmm3, [PI]
	shufps xmm3, xmm3, 0h
	subps xmm2, xmm3		; xmm2 = x = r - pi

	
	; ----- calculo la potencia de x ya procesado ------------
		movdqu xmm6, xmm2	; xmm6: x
		mulps xmm6, xmm2	; xmm6: x*x
		movdqu xmm4, xmm6	; xmm4: x*x
		mulps xmm4, xmm4	; xmm4: x*x*x*x
		movdqu xmm5, xmm4	; xmm5: x*x*x*x
		mulps xmm5, xmm6	; xmm5: x*x*x*x*x*x

		mulps xmm5, xmm2	; xmm5: x*x*x*x*x*x*x = x_7           	<------
		mulps xmm4, xmm2	; xmm4: x*x*x*x*x = x_5			<------
		mulps xmm6, xmm2	; xmm6: x*x*x = x_3			<------
	; ----- no modificar : xmm6, xmm4, xmm5 -----------------


	pxor xmm0, xmm0
	movd xmm0, [cte_seis]
	shufps xmm0, xmm0, 0h	
	cvtdq2ps xmm0, xmm0		; xmm0 = 6.0   6.0   6.0   6.0
	divps xmm6, xmm0		; x_3/6.0


	pxor xmm0, xmm0
	movd xmm0, [cte_ciento_veinte]
	shufps xmm0, xmm0, 0h	
	cvtdq2ps xmm0, xmm0		; xmm0 = 120.0   120.0   120.0   120.0
	divps xmm4, xmm0		; x_5/120.0


	pxor xmm0, xmm0
	movd xmm0, [cte_mucho]
	shufps xmm0, xmm0, 0h
	cvtdq2ps xmm0, xmm0		; xmm0 = 5040.0   5040.0   5040.0   5040.0
	divps xmm5, xmm0		; x_7/5040.0

	subps xmm2, xmm6
	addps xmm2, xmm4
	subps xmm2, xmm5

	movdqu xmm0, xmm2
	ret
